package server;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Vector;

import static shared.Status.*;

import static shared.StatusHandler.*;

public class DnDServer {

	private ServerSocket reception;
	private Socket tempClient;
	private int port;
	
	private Vector<ClientHandler> connections;
	private Vector<ClientObject> clientInfos;
	private EventManager manager = EventManager.getInstance();
	
	
	public DnDServer() {
		// TODO Auto-generated constructor stub
		this(7777);
	}
	
	public DnDServer(int port)
	{
		setPort(port);
		this.connections = new Vector<ClientHandler>();
		this.clientInfos = new Vector<ClientObject>();
	}
	
	/**
	 * Start the server
	 */
	public void start()
	{
		if(initReception())
		{
			// TODO: Delegate Status to Status Informer
			updateStatus(LISTEN,port);
			
			while (reception.isBound()) 
			{
				if(receiveClient())
				{
					updateStatus(ACCEPT, ""+tempClient.getInetAddress());
					
					// TODO: Delegate to ClientThreads
					ClientHandler handler = new ClientHandler(tempClient,clientInfos);
					connections.add(handler);
					/* TODO: Implement a Distributor Thread
							#Subscribes to every new ClientHandler thread
							Every new Client handler has to subscribe to Distributor
							Every new event from Client handler will be caught by Distributor and forwarded
							*/
					manager.addClientListener(handler);
					handler.start();
				}
			}
		}
	}
	
	/**
	 * Stop the server
	 */
	public void stop()
	{
		// TODO: Disconnect all clients
		for(ClientHandler handler: connections)
		{
			handler.killConnection();
		}
		// TODO: Clear Client List
		// TODO: Stop reception
	}
	
	/**
	 * Stop waiting for new clients
	 * @throws IOException 
	 */	
	public void stopListening() throws IOException
	{
		if(reception != null && reception.isBound()) reception.close();
	}
	
	/**
	 * Set the port to listen on
	 * @param port
	 */
	public void setPort(int port)
	{
		this.port = port;
	}
	
	/**
	 * Initialise reception and tell it to wait for clients
	 * @return TRUE, if initialisation and binding were successful
	 */
	private boolean initReception()
	{
		try
		{
			// Init and listen to port
			reception = new ServerSocket(port);
			return true;
		}
		catch(IOException io)
		{
			// TODO: Delegate to a Error Handler
			return false;
		}
	}
	
	/**
	 * Create a socket for the client received by the reception
	 * @return TRUE, if new Socket was created
	 */
	private boolean receiveClient()
	{
		
		try 
		{			
			// Create a new Socket for the client connecting			
			tempClient = reception.accept();			
			// TODO: Pass down to ClientThreads
			
			return true;
			
		}		
		catch (IOException e) 
		{
			// TODO Auto-generated catch block
			// TODO: Delegate to a Error Handler
			e.printStackTrace();
			return false;
		}
	}
	
	/**
	 * Stop the reception from accepting more clients
	 * @return TRUE, if successful
	 */
	private boolean stopReception()
	{
		try
		{
			if(reception != null && !reception.isClosed())
			{
				reception.close();
			}
			return true;
		}
		catch (IOException io) {
			// TODO: handle exception
			// TODO: Delegate to a Error Handler
			return false;
		}
	}
	
	
	
}
